/*
 * Flux JavaScript Library
 * Copyright (c) 2010 Leonardo Dutra Constancio
 * MIT License (http://jsflux.googlecode.com/svn/trunk/mit-license.txt)
 */

flux.EventDispatcher = function()
{
	if(this instanceof flux.EventDispatcher)
		this._listeners =
		{
		};
	/*listener key == event type. If no listener registered, there will be undefined/null value in listeners[type]*/
};
/*TODO enhance add, remove and dispachEventListener (3rd argument)*/
flux.EventDispatcher.prototype =
{

	hasEventListener: function(type)
	{
		return !!this._listeners[type];
	},
	addEventListener: function(type, listener, useCapture/*=false*/)
	{
		if( typeof type === 'string' && typeof listener === 'function')
		{
			useCapture = !!useCapture;
			var listeners = this._listeners[type];
			/*queue*/
			if(typeListeners)
			{
				var i = typeListeners.indexOf(listener);
				if(i !== -1 && typeListeners[i].useCapture !== useCapture)
				{
					i = typeListeners.indexOf(listener, i + 1);
				}
				if(i === -1)
				{
					typeListeners[typeListeners.length] =
					{
						useCapture: useCapture,
						listener: listener
					};
				}
			} else
				this._listeners[type] = [
				{
					useCapture: useCapture,
					listener: listener
				}];
		}
	},
	removeEventListener: function(type, listener, useCapture/*=false*/)
	{
		var typeListeners = this._listeners[type];
		if(typeListeners)
		{
			var i = typeListeners.indexOf(listener);
			if(i !== -1 && typeListeners[i].useCapture !== !!useCapture)
			{
				i = typeListeners.indexOf(listener, i + 1);
			}
			if(i !== -1)
			{
				if(typeListeners.length === 1)
					this._listeners[type] = null;
				else
					typeListeners.splice(i, 1);
			}
		}
	},
	// TODO implement event flow breaking method (aka stopPropagation)
	// TODO review event dispatching flow
	dispatchEvent: function(event)
	{
		var type;
		if( event instanceof flux.Event && ( type = event.type))
		{
			var flow = [];
			/*flow*/
			var n = 0;
			var o = (event.target = this)._parent;
			/* find flow objects till ancestor and stores */
			while(o)
			o = (flow[n++] = o)._parent;
			var length;

			while(n--)
			if(( o = (event.currentTarget = flow[n])._listeners[type]))
			{
				length = o.length;
				while(length--)
				if(o[length].useCapture)
					o[length].listener.call(this, event);
			}

			if(( o = (event.currentTarget = this)._listeners[type]))
			{
				event.eventPhase = EventPhase.TARGET_PHASE;
				length = o.length;
				while(length--)
				if(!o[length].useCapture)
					o[length].listener.call(this, event);
			}

			if(event.bubbles)
			{
				event.eventPhase = EventPhase.BUBBLING_PHASE;
				length = flow.length;
				while(++n < length)
				if(( o = (event.currentTarget = flow[n])._listeners[type]))
				{
					length = o.length;
					while(length--)
					if(!o[length].useCapture)
						o[length].listener.call(this, event);
				}
			}
		}
	}
};
